/**
 * @file swei_downlink.c
 * @brief 
 * @author  ()
 * @version 1.0
 * @date 2024-09-13
 * 
 * @copyright Copyright (C) 2019 Queclink Wireless Solutions (ShenZhen) Co., Ltd. All Rights Reserved.
 * 
 * @par 修改日志:
 * <table>
 * <tr><th>Date       <th>Version <th>Author  <th>Description
 * <tr><td>2024-09-13 <td>1.0     <td>     <td>内容
 * </table>
 */
#include "include/port/swei_log.h"
#include "include/swei_common.h"
#include "include/swei_downlink.h"
#include "include/swei_uplink.h"
#include "include/port/swei_wrapper.h"
#include "service/include/swei_cache.h"
#include "include/port/swei_fw_info.h"

#include "include/swei_package.h"
#include "include/swei_login.h"
#include "include/swei_socket.h"
#include "include/swei_crc16.h"
#include "include/swei_opcode.h"
#include "include/swei_config.h"
#include "include/swei_cmd.h"
#include "include/swei_active.h"
#include "include/swei_cache.h"

#include "utils/utils_timer.h"
#include "utils/utils.h"

typedef enum{
    MAGIC_HEADER_H,
    MAGIC_HEADER_L,
    LENGTH_H,
    LENGTH_L,
    DATA_FILL,
    CRC_CHECK_H,
    CRC_CHECK_L,
    TAIL_0x0D,
    TAIL_0x0A,
}PARSE_STEP_E;

PARSE_STEP_E prs_step_e;

typedef struct{
    uint8_t  head[2];
    uint16_t len;
    uint8_t *data;
    uint16_t crc;
    uint8_t  tail[2];   // 0x0D 0x0A
}downlink_data_t;

static int32_t  parse_protocol(uint8_t *data, uint16_t length);
static void precheck_message(uint8_t byte);

downlink_data_t dl_data = {
    0
};




/**
 * @description: 定义回调函数指针
 * @param {int} 状态值
 * @param {char} * 对应的url，有些回调函数不需要，该参数可以不处理，直接传值为null
 * @param {uint16_t} 指令的opcode，在回复命令时必须携带
 * @return {int} 见DLCMD_RET_TYPE_ENUM定义
 * @Date: 2023-10-30 09:37:40
 */

void swei_downlink_init(void)
{
    prs_step_e = MAGIC_HEADER_H;
    memset(&dl_data, 0, sizeof(downlink_data_t));

    /* 1. 激活功能初始化 */
    swei_activate_init();
}

void swei_downlink_process(void)
{
    int32_t res = 0;
    uint8_t byte[2048] = {0};

    if(!swei_socket_connect_ok())
    {
        return;
    }

    if( (res = swei_tcp_read((char *)byte, sizeof(byte))) > 0)
    { 
        for(uint16_t len = 0; len < res; len++)
        {
            precheck_message(byte[len]);
        }
    }
    else
    {
        // TODO:deal with error
    }
}

void swei_downlink_deinit(void)
{
    prs_step_e = MAGIC_HEADER_H;
    if(dl_data.data)
    {
        swei_free(dl_data.data);
    }
    memset(&dl_data, 0, sizeof(downlink_data_t));
}




/// @brief 预处理协议;待增加超时下标复位
/// @param byte 
void precheck_message(uint8_t byte)
{
    static uint16_t recv_len = 0;

    // log_v("%02x ", byte);

    switch(prs_step_e)
    {
        case MAGIC_HEADER_H:
        {
            if(byte == 0x7A)
            {
                prs_step_e++;
                dl_data.head[0] = byte;
            }
        }
        break;

        case MAGIC_HEADER_L:
        {
            if(byte == 0x7A)
            {
                prs_step_e++;
                dl_data.head[1] = byte;
            }
            else
            {
                prs_step_e = MAGIC_HEADER_H;
            }
        }
        break;

        case LENGTH_H:
        {
            dl_data.len |= (byte << 8);
            prs_step_e++;
        }
        break;

        case LENGTH_L:
        {
            dl_data.len |= byte;
            prs_step_e++;
            log_d("recv data length = %d\r\n", dl_data.len);

            if(dl_data.data != NULL)
            {
                swei_free(dl_data.data);
                dl_data.data = NULL;
            }

            recv_len = 0;
        }
        break;

        case DATA_FILL:
        {
            if(dl_data.len == 0)
            {
                prs_step_e++;
                break;
            }

            if(dl_data.data == NULL)
            {
                dl_data.data = swei_malloc(dl_data.len + 2);
                if(NULL == dl_data.data)
                {
                    // malloc failed
                    swei_downlink_deinit();
                    break;
                }


                dl_data.data[recv_len++] = dl_data.len >> 8;
                dl_data.data[recv_len++] = dl_data.len & 0xFF;
            }

            dl_data.data[recv_len++] = byte;
            // log_v("data = %02X, recv_len = %d", byte, recv_len);
            if(recv_len >= dl_data.len)
            {
                log_d("protocol data recv finish = %d", recv_len);
                prs_step_e++;
                break;
            }
        }
        break;

        case CRC_CHECK_H:
        {
            dl_data.crc |= (byte << 8);
            prs_step_e++;
        }
        break;

        case CRC_CHECK_L:
        {
            uint16_t local_crc = 0;

            dl_data.crc |= byte;
            local_crc = swei_calc_crc(dl_data.data, recv_len);
            if(local_crc != dl_data.crc)
            {
                // crc failed
                log_e("recv data crc error, local %x != %x\r\n", local_crc, dl_data.crc); 
                swei_downlink_deinit();
                break;
            }

            prs_step_e++;
        }
        break;

        case TAIL_0x0D:
        {
            if(0x0D != byte)
            {
                // crc failed
                log_e("recv data tail error != 0x0D!\r\n");
                swei_downlink_deinit();
                break;
            }

            prs_step_e++;
        }
        break;

        case TAIL_0x0A:
        {
            if(0x0A != byte)
            {
                // crc failed
                log_e("recv data tail error != 0x0A!\r\n");
                swei_downlink_deinit();
                break;
            }

            // parse message downlink;
            dl_data.data[recv_len++] = byte;
            log_d("parse_protocol, recv_len = %d\r\n", recv_len - 2);
            parse_protocol(&dl_data.data[2], recv_len - 2);  // 传入去除头信息和校验信息的数据段

            // reset the data buffer;
            swei_downlink_deinit();
        }
        break;
    }
}



static int32_t swei_netProtocol_proc_platfrom_ack(uint8_t *p_msg_data);
static int32_t swei_netProtocol_proc_request_activate_ack(uint8_t *p_msg_data);
static void swei_downlink_cmd_netprotol_handler(uint8_t *body_data);
/// @brief 协议包解析
/// @param data 
/// @param length 
/// @return 
static int32_t parse_protocol(uint8_t *data, uint16_t length)
{

    // /**************************************************************************************************
    //  *  |  包长度       | 序列号        |              包内容                                  |   crc        |   停止位         |
    //  *  | a[0]  a[1]   | a[2]  a[3]    |  a[4]  a[5]  | a[6]a[7]  | a[8] | a[9] a[10] a[11] | a[12]  a[13] | a[14]  a[15]  |
    //  *  |              |               |   协议id     |  ack_id    | 结果 |       时间戳         |              |               |
    //  *************************************************************************************************************/
      
    // /* 1. 将消息长度字段塞进p_msg_data用于计算crc */
    // p_msg_data[0] = (head_len >> 8) & 0xff;
    // p_msg_data[1] = (head_len) & 0xff;   

    // /* 计算消息crc,   去掉错误校验和停止位4个字节 */
    // calc_crc = swei_calc_crc(p_msg_data, buf_len - 4);

    // /* 2. 取得消息crc */
    // msg_crc = (p_msg_data[buf_len - 4] << 8) | p_msg_data[buf_len - 3];

    // /* 3. 校验消息crc和计算得到的crc */
    // if (calc_crc != msg_crc)
    // {
    //     log_e("tbox cmd crc error, calc_crc = 0x%x, msg_crc = 0x%x",calc_crc, msg_crc);
    //     return -1;
    // }
    // /* 获取协议id 根据协议id进入不同的业务处理入口  */
    uint16_t protocol_id = data[2] << 8 | data[3];

    log_v("recieve downlink data, length = %d, protocol id = %X\r\n", length, protocol_id);
    switch (protocol_id)
    {
        case NET_PROTOCOL_ID_PLATFORM_ACK:
            // 下行平台通用应答消息处理入口
            swei_netProtocol_proc_platfrom_ack(&data[4]); // 传入包内容
            break;

        case NET_PROTOCOL_ID_DOWNLINK:
            // 服务器下行指令入口
            swei_downlink_cmd_netprotol_handler(&data[4]); // p_msg_data + 6是数据内容
            break;

        case NET_PROTOCOL_ID_REQUEST_ACTIVATE_ACK: // 请求激活信息应答,下发设备激活状态
            swei_netProtocol_proc_request_activate_ack(&data[4]);
            break;

        default:
            log_d("unknown protocol id:%d\r\n", protocol_id);
            break;
        }

    return 0;
}

static void tbox_netProtocol_proc_warning_ack(uint8_t ack_result, uint8_t *p_msg_data);
static void tbox_netProtocol_proc_location_ack(uint8_t ack_result, uint8_t *p_msg_data);
static void tbox_netProtocol_proc_config_ack(uint8_t ack_result, uint8_t *p_msg_data);
static void tbox_netProtocol_proc_status_ack(uint8_t ack_result, uint8_t *p_msg_data);
/**
 * @description: 处理平台通用应答消息
 * @param    p_msg_data：从起始位之后的所有消息
 * @return {*}
 * @Date: 2023-08-31 11:31:47
 * @modification:
 */
static int32_t swei_netProtocol_proc_platfrom_ack(uint8_t *p_msg_data)
{
    uint16_t ack_protocol_id;
    uint8_t  ack_result;
    

    /* 获取应答协议id和应答结果,
     * 重要说明:基于当前的业务模型, 没有必要对每个消息的应答进行处理,目前这里仅处理登录消息和心跳消息的应答
     * 如果某个业务消息必须要等待服务器端的应答,则需要对应的业务开发者自行处理(在这里加上对应消息的应答处理)*/
    ack_protocol_id = (p_msg_data[0] << 8) | p_msg_data[1];
    ack_result = p_msg_data[2];
    switch (ack_protocol_id)
    {
        case NET_PROTOCOL_ID_LOGSTEP_NEW:   /* 登录报文通用应答 */
        {
            // tbox_netProtocol_proc_login_ack(ack_result, p_msg_data);
            log_i("<< tbox recv login ack from server!");
            if(0 == ack_result)
            {
                swei_srv_login_ack_set();
            }
        }
        break;

        case NET_PROTOCOL_ID_HEART_BEAT:
        {
            // tbox_netProtocol_proc_heartbeat_ack(ack_result, p_msg_data);
            log_i("<< tbox recv hearbeat ack from server!");
            swei_srv_login_ack_set();
        }
        break;

        case NET_PROTOCOL_ID_REQUEST_ACTIVATE:
        {
            log_i("<< tbox recv active ack from server!");
            swei_srv_login_ack_set();
        }
        break;

        case NET_PROTOCOL_ID_WARNING:
        {
            log_i("<< tbox recv warning ack from server!");
            tbox_netProtocol_proc_warning_ack(ack_result, p_msg_data);
        }
        break;

        case NET_PROTOCOL_ID_GPS:
        case NET_PROTOCOL_ID_LBS:
        case NET_PROTOCOL_ID_WIFI:
        {
            log_i("<< tbox recv location ack from server!");
            tbox_netProtocol_proc_location_ack(ack_result, p_msg_data);
        }
        break;

        case NET_PROTOCOL_ID_DEVICE_STATUS:
        {
            log_i("<< tbox recv status ack from server!");
            tbox_netProtocol_proc_status_ack(ack_result, p_msg_data);
        }   
        break;

        case NET_PROTOCOL_ID_UPLOAD_CONFIG_INFO: // 配置信息上传应答
        {
            tbox_netProtocol_proc_config_ack(ack_result, p_msg_data);
        }
        break;

        default:
            /* 增加其他消息处理 */
            break;
    }
    return 0;
}

/**
 * @description: 请求激活信息应答,下发设备激活状态
 * @param    p_msg_data：从起始位之后的所有消息
 * @return {*}
 * @Date: 2023-08-31 11:31:47
 * @modification:
 */
static int32_t swei_netProtocol_proc_request_activate_ack(uint8_t *p_msg_data)
{
    uint8_t *data_body = p_msg_data;         // 消息id后面的内容
    uint8_t activate_flag = 0;
    uint32_t activate_time = 0;
    uint32_t uuid = 0;

    activate_time = (data_body[0] << 24) | (data_body[1] << 16) | (data_body[2] << 8) | data_body[3];
    uuid = (data_body[4] << 24) | (data_body[5] << 16) | (data_body[6] << 8) | data_body[7];
    activate_flag = data_body[8];

    log_i("tbox activate_time[%08x].uuid[%08x].activate_flag[%d]", activate_time, uuid, activate_flag);

    /* 根据UUID确定当前设备的激活模式 */
    swei_activate_device_proc(uuid, activate_flag);

    /* 激活请求响应完成, 不需要再次执行激活请求 */
    swei_srv_active_req_set_finish();

    return 0;
}

/**
 * @description: 设备回复平台指令的通用应答,通用应答仅表示设备成功收到了指令
 * @param {short} cmd_id
 * @param {int} ret
 * @return {*}
 * @Date: 2023-10-20 17:16:59
 * @modification:
 */
static void swei_netProtocol_send_device_general_ack(const uint16_t cmd_id, const int ret, const uint16_t cmd_opcode)
{
    typedef struct
    {
        uint8_t ack_msg[16];
        uint8_t ack_len;
    } MSG_INFO;
    MSG_INFO  msg_info;
    uint8_t   ack_len = 0;
    uint8_t   ack_send_msg[32] = {0};
    int       result = 0;
    unsigned int       timestamp;
    
    /* 1.封装消息 */
    memset(&msg_info, 0, sizeof(msg_info));

    /* 应答id */
    msg_info.ack_msg[ack_len++] = (cmd_id >> 8) & 0xff;
    msg_info.ack_msg[ack_len++] = cmd_id & 0xff;

    msg_info.ack_msg[ack_len++] = (cmd_opcode >> 8) & 0xff;
    msg_info.ack_msg[ack_len++] = cmd_opcode & 0xff;
    
    /* 应答结果 */
    msg_info.ack_msg[ack_len++] = ret & 0xff;

    /* 时间戳 */
    timestamp = swei_get_device_timestamp();
    ack_len += bigending2buf(msg_info.ack_msg + ack_len, timestamp);

    msg_info.ack_len = ack_len;

    ack_len = swei_package_protocol_msg(NULL, (uint8_t *)&msg_info, NET_PROTOCOL_ID_DEVICE_ACK, ack_send_msg);
    if (ack_len <= 0)
    {
        log_e("tbox package device general ack fail,[send_len:%d, ack_cmd:%d]", ack_len, cmd_id);
        return;
    }

#if 0
    /* 3. 句柄获取到之后就发送消息, to-do:根据返回值检查发送结果  */
    result = swei_tcp_write(ack_send_msg, ack_len);
    if (result <= 0)
    {
        log_e("tbox package device general ack fail, [result:%d, ack_cmd:%d]", result,cmd_id);
    }
#else
    swei_datatype_t dt = {0};

    dt.data_ptr = qlmalloc(ack_len);
    if (NULL == dt.data_ptr) {
        log_e("device ack request malloc failed!\r\n");
        return;
    }
    
    memcpy(dt.data_ptr, ack_send_msg, ack_len);
    dt.data_len = ack_len;
    dt.data_type = TYPE_DEVICE_ACK;

    if (0 != swei_base_cache_push(&dt)) { 
        log_e("tbox package device general ack fail, [result:%d, ack_cmd:%d]", result,cmd_id);
        if (dt.data_ptr) {
            qlfree(dt.data_ptr);
        }
        
        return;
    }
#endif
}




/**
 * @description: 回复日志文件上传的指令(0x000B),仅仅做个外部接口的封装而已,(重复代码)后续再优化合并
 * @param {short} cmd_id 指令ID
 * @param {int} ret  定义参见 TBOX_CMD_ACK_RESULT
 * @return {void}
 * @Date: 2023-10-20 17:16:59
 * @modification:
 */
void swei_netProtocol_ack_downlink_cmd(uint16_t cmd_id, TBOX_CMD_ACK_RESULT ret, bool clear_id_flag)
{
    typedef struct
    {
        uint8_t ack_msg[16];
        uint8_t ack_len;
    } MSG_INFO;
    MSG_INFO  msg_info;
    uint8_t   ack_len = 0;
    uint8_t   ack_send_msg[32] = {0};
    int       result = 0;
    unsigned int       timestamp;
    uint16_t  cmd_opcode = 0;
    
    /* 1.封装消息 */
    memset(&msg_info, 0, sizeof(msg_info));

    /* 应答id */
    msg_info.ack_msg[ack_len++] = (cmd_id >> 8) & 0xff;
    msg_info.ack_msg[ack_len++] = cmd_id & 0xff;

    /* 获取指令操作码,此时是设备指令处理完成之后应答需要清除 */
    result = tbox_netprotocol_get_cmd_opcode(cmd_id, &cmd_opcode, clear_id_flag);
    if (result != SUCC)
    {
        /* 不要返回错误,虽然opcode有问题但指令可以正常执行,后续根据实际业务需要再确定是否需要严格限制 */
        log_e("ack downlink cmd get opcode fail, [cmd_id:0x%x opcode:0x%x]",cmd_id,cmd_opcode);
    }
    msg_info.ack_msg[ack_len++] = (cmd_opcode >> 8) & 0xff;
    msg_info.ack_msg[ack_len++] = cmd_opcode & 0xff;
    
    /* 应答结果 */
    msg_info.ack_msg[ack_len++] = ret & 0xff;

    /* 时间戳 */
    timestamp = swei_get_device_timestamp();
    ack_len += bigending2buf(msg_info.ack_msg + ack_len, timestamp);

    msg_info.ack_len = ack_len;

    ack_len = swei_package_protocol_msg(NULL, (uint8_t *)&msg_info, NET_PROTOCOL_ID_DEVICE_CMD_ACK, ack_send_msg);
    if (ack_len <= 0)
    {
        log_e("tbox package ack downlink msg fail, ack_len:%d ack_cmd:%d", ack_len, cmd_id);
        return;
    }

#if 0
    /* 3. 句柄获取到之后就发送消息, to-do:根据返回值检查发送结果  */
    result = swei_tcp_write(ack_send_msg, ack_len);
    if (result <= 0)
    {      
        log_e("tbox send ack downlink msg fail, result:%d ack_cmd:%d", result, cmd_id);
    }
    else
    { 
        log_i("tbox send ack downlink cmd SUCC, ack_cmd:%d, ret:%d",cmd_id,ret);
    }
#else
    // 头插cache进行发送
    swei_datatype_t dt = {0};

    dt.data_ptr = qlmalloc(ack_len);
    if (NULL == dt.data_ptr) {
        log_e("deivce ack request malloc failed!\r\n");
        return;
    }
    
    memcpy(dt.data_ptr, ack_send_msg, ack_len);
    dt.data_len = ack_len;
    dt.data_type = TYPE_DEVICE_ACK;

    if (0 != swei_base_cache_push(&dt)) { 
        log_e("tbox send ack downlink msg fail, result:%d ack_cmd:%d", result, cmd_id);
        if (dt.data_ptr) {
            qlfree(dt.data_ptr);
        }
        
        return;
    }
#endif
}


/**
 * @description: 处理下行的指令
 * @param {uint8_t} *body_data
 * @return {*}
 * @Date: 2023-10-18 20:08:37
 * @modification:
 */
static void swei_downlink_cmd_netprotol_handler(uint8_t *body_data)
{
    int32_t ret = 0;
    const uint8_t CMD_CONTENT_START_POS = 6; // 指令内容起始位置
    /* 获取cmd_id */
    uint16_t cmd_id = body_data[0] << 8 | body_data[1];
    /* 获取指令对应的操作码 */
    uint16_t cmd_opcode = body_data[2] << 8 | body_data[3];
    /* 指令内容长度 */
    uint16_t cmd_content_len = body_data[4] << 8 | body_data[5];

    log_i("tbox recv downlink cmd,[cmd_id:0x%x] [opcode:0x%x] [cmd_len:%d]", cmd_id, cmd_opcode, cmd_content_len);

    // /* 在低功耗模式时要退出睡眠,同时设置业务正在处理业务标志 */
    // swei_netProtocol_check_need_quit_sleep_for_proc_cmd(1);

    /* 先保存cmd_id和opcode之间的对应关系 */
    ret = tbox_netprotocol_save_cmd_opcode(cmd_id, cmd_opcode);  
    if (ret != SUCC)
    {
       /* 容错处理,暂时不返回仅做log日志记录 */
       log_e("sava cmd opcode fail,[cmd_id:%d] [opcode:0x%x]",cmd_id, cmd_opcode);
    }
    
    /* 收到服务器下行指令马上回复通用应答0x0009, 表示设备收到,页面上不再等待 */
    swei_netProtocol_send_device_general_ack(cmd_id, ret, cmd_opcode);

    // /* 如需要配置修改的，先进行配置修改 */
    int32_t cfg_ret = swei_config_deal_cmd(cmd_id, body_data + CMD_CONTENT_START_POS, cmd_content_len);
    if (cfg_ret != CMD_SUCCESS && cfg_ret != CMD_NOT_SUPPORT)
    {
        log_e("save config error. ret=%d", cfg_ret);
        swei_netProtocol_ack_downlink_cmd(cmd_id, cfg_ret == CMD_FAILURE ? CMD_FAILURE : CMD_MSG_ERR, true);  
        return;
    }
    
    DLCMD_RET_TYPE_ENUM cb_ret = swei_downlink_cmd_handler((DOWN_LINK_CMD_ENUM)cmd_id, 
                                                                cmd_opcode, 
                                                                body_data + CMD_CONTENT_START_POS, 
                                                                cmd_content_len);
    switch(cb_ret)
    {
        case DLCMD_RET_FINISH:
            swei_netProtocol_ack_downlink_cmd(cmd_id, CMD_SUCCESS, true);    // 设备通用应答0x000B (0成功)
            // swei_netProtocol_check_need_quit_sleep_for_proc_cmd(0);          // 指令处理完毕,在低功耗模式检查是否需要继续睡眠
            break;
        case DLCMD_RET_ERROR:
            swei_netProtocol_ack_downlink_cmd(cmd_id, CMD_FAILURE, true);    // 设备通用应答0x000B (1失败)
            // swei_netProtocol_check_need_quit_sleep_for_proc_cmd(0);          // 指令处理完毕,在低功耗模式检查是否需要继续睡眠
            break;
        case DLCMD_RET_CONTINUE:
            log_i("cmd for future process.");
            break;
        case DLCMD_NOT_SUPPORT:
            log_w("no handler for cmdid=0x%x", cmd_id);
            swei_netProtocol_ack_downlink_cmd(cmd_id, CMD_NOT_SUPPORT, true);    // 设备通用应答0x000B (3不支持)
            // swei_netProtocol_check_need_quit_sleep_for_proc_cmd(0);          // 指令处理完毕,在低功耗模式检查是否需要继续睡眠
            break;
        case DLCMD_IS_OTA:
            swei_netProtocol_ack_downlink_cmd(cmd_id, CMD_IN_OTA, true);    // 设备通用应答0x000B (4当前处于OTA文件下载过程)
        default:
            log_e("illegal return value for cmd handler[cmdid=0x%x, cb_ret=%d]", cmd_id, cb_ret);
            swei_netProtocol_ack_downlink_cmd(cmd_id, CMD_FAILURE, true);    // 设备通用应答0x000B (1失败)
            // swei_netProtocol_check_need_quit_sleep_for_proc_cmd(0);          // 指令处理完毕,在低功耗模式检查是否需要继续睡眠
    }

    return;
}



/**
 * @description: 陀螺仪告警信息应答,如果没有应答说明上传失败
 * @param    p_msg_data
 * @return {*}
 * @Date: 2023-08-31 11:31:47
 * @modification: */
static void tbox_netProtocol_proc_warning_ack(uint8_t ack_result, uint8_t *p_msg_data)
{
    if(p_msg_data == NULL)
    {
        log_e("invalid para");
        return ;
    }

    int serial_num = p_msg_data[2] << 8 | p_msg_data[3];

    log_i("tbox recv request warning ack from server, serial_num :%04x", serial_num);

    swei_uplink_ack_proc(TYPE_ALARM, serial_num);
}

static void tbox_netProtocol_proc_location_ack(uint8_t ack_result, uint8_t *p_msg_data)
{
    if(p_msg_data == NULL)
    {
        log_e("invalid para");
        return ;
    }

    int serial_num = p_msg_data[2] << 8 | p_msg_data[3];

    log_i("tbox recv request location ack from server, serial_num :%04x", serial_num);

    swei_uplink_ack_proc(TYPE_LOC, serial_num);
}


/**
 * @brief 平台配置应答处理
 * @param  ack_result       My Param doc
 * @param  p_msg_data       My Param doc
 */
static void tbox_netProtocol_proc_config_ack(uint8_t ack_result, uint8_t *p_msg_data)
{
    if(p_msg_data == NULL)
    {
        log_e("invalid para");
        return ;
    }

    int serial_num = p_msg_data[2] << 8 | p_msg_data[3];

    log_i("tbox recv request config ack from server, serial_num :%04x", serial_num);

    swei_uplink_ack_proc(TYPE_CONFIG, serial_num);

    // swei_config_report_trigger_next();
}


/**
 * @brief 平台状态应答处理
 * @param  ack_result       My Param doc
 * @param  p_msg_data       My Param doc
 */
static void tbox_netProtocol_proc_status_ack(uint8_t ack_result, uint8_t *p_msg_data)
{
    if(p_msg_data == NULL)
    {
        log_e("invalid para");
        return ;
    }

    int serial_num = p_msg_data[2] << 8 | p_msg_data[3];

    log_i("tbox recv request status ack from server, serial_num :%04x", serial_num);

    swei_uplink_ack_proc(TYPE_STATUS, serial_num);
}